<template>
  <n-descriptions label-placement="left" separator=" "
                  :column="1" bordered>
    <n-descriptions-item label="PRTS">
      <a v-if="prtsHref" :href="prtsHref" target="_blank">PRTS干员页面</a>
    </n-descriptions-item>
    <n-descriptions-item label="技能周期">
      <n-space>
        <n-tag v-for="tag in periodList" size="large" :type="tag.type">
          {{ tag.text }}
        </n-tag>
        <n-tag v-if="hasTag('infinity')" size="large" type="info">
          持续时间无限
        </n-tag>
        <n-tag v-if="hasTag('passive')" size="large">
          被动
        </n-tag>
        <n-tag v-if="hasTag('instant')" size="large" type="info">
          瞬发
        </n-tag>
        <n-tag v-if="hasTag('auto')" size="large" type="warning">
          落地点火
        </n-tag>
        <n-tag v-if="hasTag('hit')" size="large" type="warning">
          受击回复
        </n-tag>
      </n-space>
    </n-descriptions-item>
    <n-descriptions-item label="技能攻击力">
      <n-text :type="s_atk.type">{{ s_atk.value }} </n-text>
    </n-descriptions-item>
    <n-descriptions-item :label="skillDamage.title">
      <n-space>
        {{ skillDamage.value }}
        <n-tag v-if="skillDamage.value != ''" type="success" size="large">
          直接: {{ skillDamage.hit }}
        </n-tag>
        <n-tag v-if="skillDamage.hasCrit" type="error" size="large">
          暴击: {{ skillDamage.crit }}
        </n-tag>
        <n-tag v-if="skillDamage.hasExtra" type="info" size="large">
          额外: {{ skillDamage.extra }}
        </n-tag>
        <n-tag v-if="hasTag('reflect')" size="large">
          反射伤害
        </n-tag>
      </n-space>
    </n-descriptions-item>
    <n-descriptions-item :label="skillDps.title">
      <n-space align="center">
        <n-text :type="skillDps.type">{{ skillDps.value }} </n-text>
        <n-tag v-if="hasTag('instant')" size="large" type="info">
          瞬发
        </n-tag>
      </n-space>
    </n-descriptions-item>
    <n-descriptions-item :label="normalDps.title">
      <n-text :type="normalDps.type">{{ normalDps.value }} </n-text>
    </n-descriptions-item>
    <n-descriptions-item :label="globalDps.title">
      <n-text :type="globalDps.type">{{ globalDps.value }} </n-text>
    </n-descriptions-item>
    <n-descriptions-item label="技能攻击间隔">
      {{ skillAttackTime }}
    </n-descriptions-item>
    <n-descriptions-item label="普攻攻击间隔">
      {{ normalAttackTime }}
    </n-descriptions-item>
    <n-descriptions-item label="计算过程">
    </n-descriptions-item>
  </n-descriptions>
  <pre v-if="debug">{{ props.dps }}</pre>
</template>

<script lang="ts" setup>
import { computed, ref, watch, h } from 'vue'
import { computedAsync } from '@vueuse/core'
import { NDescriptions, NDescriptionsItem, NSpace,
         NText, NTag,
       } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { Maybe } from 'purify-ts/Maybe'

// 传给该组件的参数，使用toRef取得响应式引用
// 值修改emit给上层组件
const props = defineProps({
  dps: { type: Object, default: null },
  showHeader: { type: Boolean, default: true },
  debug: { type: Boolean, default: false }
})

//const emit = defineEmits([])

// local functions
// looks like lodash pick()?
const pick = (obj: any, keys: string[]): any => 
  keys.reduce((ret: any, k: string) => (ret[k] = obj[k], ret), {})

// script setup上下文中不能使用Vue.$t，必须单独引入
const { t, locale } = useI18n()

// 断言dps对象是否有效
const dpsMaybe = () => Maybe.fromPredicate(x => ('normal' in x && 'skill' in x), props.dps)
const prtsHref = computed(() => dpsMaybe().map(d => `http://prts.wiki/w/${d.charName}#.E6.8A.80.E8.83.BD`)
                                          .orDefault(null))
// 技能周期标签
const periodTag = (x: number, type: string, prefix: string) => 
  x != 0 ? { type, text: `${prefix} ${Math.round(x*100)/100}s` } : null

// 伤害类型对应n-text type tag
const damageColor = ['default', 'info', 'success', 'warning', 'default']
const damageSuffix = ['DPS', 'DPS', 'HPS', 'DPS', 'HPS']

const periodList = computed(() => dpsMaybe().map(d => [
    periodTag(d.normal.dur.stunDuration, 'error', '眩晕'),
    periodTag(d.normal.dur.duration, 'success', '普攻'),
    periodTag(d.skill.dur.prepDuration, 'info', '准备'),
    periodTag(d.skill.dur.duration, 'warning', '技能')
  ].filter(x => x)
  ).orDefault([]) )

const s_atk = computed(() => dpsMaybe().map(d => ({ 
  value: Math.round(d.skill.atk),
  type: damageColor[d.skill.damageType]
})).orDefault({
  value: '-',
  type: 'default'
}))

const dpsText = (x: any, prefix: string) => {
  let value = Math.round(x.dps || x.hps)
  if (x.hps != 0 && x.dps != 0)
    value = `DPS: ${Math.round(x.dps)} / HPS: ${Math.round(x.hps)}`
  return {
    title: prefix + damageSuffix[x.damageType],
    value,
    type: damageColor[x.damageType]
  }
}
const normalDps = computed(() => dpsMaybe().map(
  d => dpsText(d.normal, '普攻')
  ).orDefault({
    title: '普攻',
    value: '',
    type: 'default'
  })
)
const skillDps = computed(() => dpsMaybe().map(
  d => dpsText(d.skill, '技能')
  ).orDefault({
    title: '技能',
    value: '',
    type: 'default'
  })
)
const globalDps = computed(() => dpsMaybe().map(
  d => dpsText({
    dps: d.globalDps,
    hps: d.globalHps,
    damageType: d.normal.damageType
  }, '平均')
  ).orDefault({
    title: '平均',
    value: '',
    type: 'default'
  })
)
const skillDamage = computed(() => dpsMaybe().map(d => {
  const _ = d.skill
  if (_.damageType != 2) {
    return {
      title: '技能总伤害',
      value: Math.round(_.totalDamage),
      hit: `${_.hitDamage.toFixed(1)} x ${_.dur.hitCount}`,
      hasCrit: _.critDamage > 0,
      crit: `${_.critDamage.toFixed(1)} x ${_.dur.critHitCount}`,
      hasExtra: _.extraDamage != 0,
      extra: _.extraDamage.toFixed(1)
    }
  } else {
    return {
      title: '技能总治疗',
      value: Math.round(_.totalHeal),
      hit: `${_.hitDamage.toFixed(1)} x ${_.dur.hitCount}`,
      hasCrit: false,
      hasExtra: _.extraHeal != 0,
      extra: _.extraHeal.toFixed(1)
    }
  }
}).orDefault({
  title: '技能总伤害',
  value: '',
  hit: '',
  hasCrit: false,
  hasExtra: false
}))

const skillAttackTime = computed(() => dpsMaybe().map(d => 
  `${d.skill.attackTime?.toFixed(3)} s / ${d.skill.frame} 帧`
).orDefault(''))
const normalAttackTime = computed(() => dpsMaybe().map(d => 
  `${d.normal.attackTime?.toFixed(3)} s / ${d.normal.frame} 帧`
).orDefault(''))

const durationTags = computed(() => dpsMaybe().map(d => d.skill.dur.tags).orDefault([]))
const hasTag = (t: string): boolean => durationTags.value.includes(t)
</script>

<style scoped>

</style>
